add support for dynamic formats (#1005)
authortsteven4 <13596209+tsteven4@users.noreply.github.com>
Mon, 20 Feb 2023 15:05:24 +0000 (08:05 -0700)
committerGitHub <noreply@github.com>
Mon, 20 Feb 2023 15:05:24 +0000 (08:05 -0700)
* de-duplicate format setup in find_vec

* create a class to pass format info pack and forth from vecs.

This simplifies re-initialization of a format, which main already
did in a few cases.

The operator overloads for the format info class make the transition
simplier.

* return empty braced init list from find_vecs when not found.

* dynamic format checkpoint.

* delete static GeoFormat instance.

* support dynamic xcsv format.

allow dynamic formats to use rd_init, rd_deinit, wr_init, wr_denint.
This makes conversion to dynamic formats easier as we can, but aren't
forced to move the old init/deinit code.
Often rd/wr_init is intertwined with rd/wr_posn_init.

use dynamic xcsv format.
fix undiscovered bug releated to option order. We assumed an order
of -i -f -o -F, but -i -o -f -F can cause errors if both formats
are style based.
test for above bug added to iblue747.test.

* add missing reference

* use template for format factories.

* correct vecs includes

* fix another filename parameter for positional args issue.

* make Vecs::prepare_format static.

* move prepare_format call to just before xxx_init

for both static and dynamic formats.

format.h
garmin.cc
geo.cc
geo.h
main.cc
reference/track/iblue747~csv.csv [new file with mode: 0644]
testo.d/geo.test
testo.d/iblue747.test
vecs.cc
vecs.h
xcsv.h

index 44ef808134140be6bc5adf8153fdaa0dec0d3516..01e887b820afdb2958e8f3de61c160c37f6f3ffe 100644 (file)
--- a/format.h
+++ b/format.h
@@ -45,6 +45,7 @@ class Format
 {
 public:
   Format() = default;
+  Format(const QString& filename) : fname{filename} {}
   // Provide virtual public destructor to avoid undefined behavior when
   // an object of derived class type is deleted through a pointer to
   // its base class type.
@@ -169,6 +170,8 @@ public:
   virtual ff_type get_type() const = 0;
   virtual QVector<ff_cap> get_cap() const = 0;
 
+  QString fname;
+
 protected:
   template <class MyFormat>
   class RteHdFunctor
index 59db848ef74c4323a3110166577d4300ef0cdff3..fb9a8cdae903a6d7355ef7e919d0dd5af070f5e3 100644 (file)
--- a/garmin.cc
+++ b/garmin.cc
@@ -81,7 +81,7 @@ static int categorybits;
 static int receiver_must_upper = 1;
 static QTextCodec* codec{nullptr};
 
-static Format* gpx_vec;
+static Vecs::fmtinfo_t gpx_vec;
 
 #define MILITANT_VALID_WAYPT_CHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
 
@@ -355,10 +355,12 @@ rd_init(const QString& fname)
 {
   if (setjmp(gdx_jmp_buf)) {
     const gdx_info* gi = gdx_get_info();
-    gpx_vec = Vecs::Instance().find_vec("gpx").fmt;
+    // FIXME: dynamic not implemented.
+    gpx_vec = Vecs::Instance().find_vec("gpx");
+    Vecs::prepare_format(gpx_vec);
     gpx_vec->rd_init(gi->from_device.canon);
   } else {
-    gpx_vec = nullptr;
+    gpx_vec = Vecs::fmtinfo_t();
     rw_init(fname);
   }
 }
diff --git a/geo.cc b/geo.cc
index 37dd6c627020b04ef3a88fc25fb4a2e111dacbd1..808a96121a17833d8ba598cfe5645f9ab49ca490 100644 (file)
--- a/geo.cc
+++ b/geo.cc
@@ -84,19 +84,9 @@ void GeoFormat::GeoReadLoc(QXmlStreamReader& reader) const
   }
 }
 
-void GeoFormat::rd_init(const QString& fname)
-{
-  geo_fname = fname;
-}
-
-void GeoFormat::rd_deinit()
-{
-  geo_fname.clear();
-}
-
 void GeoFormat::read()
 {
-  gpsbabel::File ifile = gpsbabel::File(geo_fname);
+  gpsbabel::File ifile = gpsbabel::File(fname);
   ifile.open(QIODevice::ReadOnly);
   QXmlStreamReader reader = QXmlStreamReader(&ifile);
 
@@ -143,16 +133,6 @@ Geocache::container_t GeoFormat::wpt_container(const QString& args)
   return v;
 }
 
-void GeoFormat::wr_init(const QString& fname)
-{
-  geo_fname = fname;
-}
-
-void GeoFormat::wr_deinit()
-{
-  geo_fname.clear();
-}
-
 void GeoFormat::geo_waypt_pr(const Waypoint* waypointp, QXmlStreamWriter& writer)
 {
   writer.writeStartElement(QStringLiteral("waypoint"));
@@ -221,7 +201,7 @@ void GeoFormat::geo_waypt_pr(const Waypoint* waypointp, QXmlStreamWriter& writer
 
 void GeoFormat::write()
 {
-  gpsbabel::File ofile = gpsbabel::File(geo_fname);
+  gpsbabel::File ofile = gpsbabel::File(fname);
   ofile.open(QIODevice::WriteOnly | QIODevice::Text);
   QXmlStreamWriter writer = QXmlStreamWriter(&ofile);
 
diff --git a/geo.h b/geo.h
index 8545c6c10e6dc3c21e2a2a80abf4d7f0c50fce80..884b47cdd0acc582bca49ed714a69949d9ba0dcc 100644 (file)
--- a/geo.h
+++ b/geo.h
@@ -32,6 +32,8 @@
 class GeoFormat : public Format
 {
 public:
+  using Format::Format;
+
   QVector<arglist_t>* get_args() override
   {
     return &geo_args;
@@ -47,12 +49,12 @@ public:
     return { (ff_cap)(ff_cap_read | ff_cap_write), ff_cap_none, ff_cap_none };
   }
 
-  void rd_init(const QString& fname) override;
+  void rd_init(const QString& fname) override
+  {}
   void read() override;
-  void rd_deinit() override;
-  void wr_init(const QString& fname) override;
+  void wr_init(const QString& fname) override
+  {}
   void write() override;
-  void wr_deinit() override;
 
 private:
 
@@ -66,7 +68,6 @@ private:
 
   char* deficon = nullptr;
   char* nuke_placer{};
-  QString geo_fname;
 
   QVector<arglist_t> geo_args = {
     {"deficon", &deficon, "Default icon name", nullptr, ARGTYPE_STRING, ARG_NOMINMAX, nullptr },
diff --git a/main.cc b/main.cc
index 809e057f67e259ce5ef6d4229a7f8490e7eb0cae..af61aa3e4f3d8d80819f2b4de3d74216663dad37 100644 (file)
--- a/main.cc
+++ b/main.cc
@@ -244,6 +244,57 @@ private:
   short_handle mkshort_handle;
 };
 
+static void
+run_reader(Vecs::fmtinfo_t& ivecs, const QString& fname)
+{
+  start_session(ivecs.fmtname, fname);
+  if (ivecs.isDynamic()) {
+    ivecs.fmt = ivecs.factory(fname);
+    Vecs::init_vec(ivecs.fmt);
+    Vecs::prepare_format(ivecs);
+
+    ivecs->rd_init(fname);
+    ivecs->read();
+    ivecs->rd_deinit();
+
+    Vecs::exit_vec(ivecs.fmt);
+    delete ivecs.fmt;
+    ivecs.fmt = nullptr;
+  } else {
+    /* reinitialize xcsv in case two formats that use xcsv were given */
+    Vecs::prepare_format(ivecs);
+
+    ivecs->rd_init(fname);
+    ivecs->read();
+    ivecs->rd_deinit();
+  }
+}
+
+static void
+run_writer(Vecs::fmtinfo_t& ovecs, const QString& ofname)
+{
+  if (ovecs.isDynamic()) {
+    ovecs.fmt = ovecs.factory(ofname);
+    Vecs::init_vec(ovecs.fmt);
+    Vecs::prepare_format(ovecs);
+
+    ovecs->wr_init(ofname);
+    ovecs->write();
+    ovecs->wr_deinit();
+
+    Vecs::exit_vec(ovecs.fmt);
+    delete ovecs.fmt;
+    ovecs.fmt = nullptr;
+  } else {
+    /* reinitialize xcsv in case two formats that use xcsv were given */
+    Vecs::prepare_format(ovecs);
+
+    ovecs->wr_init(ofname);
+    ovecs->write();
+    ovecs->wr_deinit();
+  }
+}
+
 static int
 run(const char* prog_name)
 {
@@ -342,10 +393,7 @@ run(const char* prog_name)
         global_opts.masked_objective |= WPTDATAMASK;
       }
 
-      start_session(ivecs.fmtname, fname);
-      ivecs->rd_init(fname);
-      ivecs->read();
-      ivecs->rd_deinit();
+      run_reader(ivecs, fname);
 
       did_something = true;
       break;
@@ -361,9 +409,7 @@ run(const char* prog_name)
           global_opts.masked_objective |= WPTDATAMASK;
         }
 
-        ovecs->wr_init(ofname);
-        ovecs->write();
-        ovecs->wr_deinit();
+        run_writer(ovecs, ofname);
 
       }
       break;
@@ -532,21 +578,11 @@ run(const char* prog_name)
       global_opts.masked_objective |= WPTDATAMASK;
     }
 
-    /* reinitialize xcsv in case two formats that use xcsv were given */
-    Vecs::Instance().prepare_format(ivecs);
-
-    start_session(ivecs.fmtname, qargs.at(0));
-    ivecs->rd_init(qargs.at(0));
-    ivecs->read();
-    ivecs->rd_deinit();
+    run_reader(ivecs, qargs.at(0));
 
     if (qargs.size() == 2 && ovecs) {
-      /* reinitialize xcsv in case two formats that use xcsv were given */
-      Vecs::Instance().prepare_format(ovecs);
 
-      ovecs->wr_init(qargs.at(1));
-      ovecs->write();
-      ovecs->wr_deinit();
+      run_writer(ovecs, qargs.at(1));
 
     }
   } else if (!qargs.isEmpty()) {
@@ -576,7 +612,18 @@ run(const char* prog_name)
     if (fname.isEmpty()) {
       fatal("An input file (-f) must be specified.\n");
     }
+
+    if (ivecs.isDynamic()) {
+      ivecs.fmt = ivecs.factory(fname);
+      Vecs::init_vec(ivecs.fmt);
+    }
+    if (ovecs && ovecs.isDynamic()) {
+      ovecs.fmt = ovecs.factory(ofname);
+      Vecs::init_vec(ovecs.fmt);
+    }
+
     start_session(ivecs.fmtname, fname);
+    Vecs::prepare_format(ivecs);
     ivecs->rd_position_init(fname);
 
     if (global_opts.masked_objective & ~POSNDATAMASK) {
@@ -588,6 +635,7 @@ run(const char* prog_name)
     }
 
     if (ovecs) {
+      Vecs::prepare_format(ovecs);
       ovecs->wr_position_init(ofname);
     }
 
@@ -611,10 +659,23 @@ run(const char* prog_name)
         delete wpt;
       }
     }
+    Vecs::prepare_format(ivecs);
     ivecs->rd_position_deinit();
     if (ovecs) {
+      Vecs::prepare_format(ovecs);
       ovecs->wr_position_deinit();
     }
+
+    if (ovecs && ovecs.isDynamic()) {
+      Vecs::exit_vec(ovecs.fmt);
+      delete ovecs.fmt;
+      ovecs.fmt = nullptr;
+    }
+    if (ivecs.isDynamic()) {
+      Vecs::exit_vec(ivecs.fmt);
+      delete ivecs.fmt;
+      ivecs.fmt = nullptr;
+    }
     return 0;
   }
 
diff --git a/reference/track/iblue747~csv.csv b/reference/track/iblue747~csv.csv
new file mode 100644 (file)
index 0000000..1ba0a39
--- /dev/null
@@ -0,0 +1,747 @@
+51.31177, 12.41318, 
+51.31181, 12.41290, 
+51.31188, 12.41277, 
+51.31216, 12.41226, 
+51.31224, 12.41238, 
+51.31225, 12.41242, 
+51.31229, 12.41249, 
+51.31263, 12.41285, 
+51.31272, 12.41282, 
+51.31281, 12.41274, 
+51.31281, 12.41272, 
+51.31274, 12.41275, 
+51.31272, 12.41270, 
+51.31276, 12.41279, 
+51.31285, 12.41296, 
+51.31296, 12.41307, 
+51.31305, 12.41318, 
+51.31309, 12.41302, 
+51.31298, 12.41302, 
+51.31301, 12.41301, 
+51.31299, 12.41297, 
+51.31302, 12.41302, 
+51.31298, 12.41320, 
+51.31306, 12.41312, 
+51.31298, 12.41302, 
+51.31290, 12.41297, 
+51.31285, 12.41296, 
+51.31280, 12.41294, 
+51.31250, 12.41312, 
+51.31246, 12.41288, 
+51.31275, 12.41253, 
+51.31296, 12.41317, 
+51.31288, 12.41324, 
+51.31286, 12.41324, 
+51.31282, 12.41331, 
+51.31284, 12.41328, 
+51.31283, 12.41331, 
+51.31279, 12.41334, 
+51.31278, 12.41333, 
+51.31276, 12.41334, 
+51.31282, 12.41332, 
+51.31292, 12.41344, 
+51.31299, 12.41379, 
+51.31304, 12.41381, 
+51.31305, 12.41384, 
+51.31311, 12.41385, 
+51.31321, 12.41388, 
+51.31329, 12.41397, 
+51.31329, 12.41405, 
+51.31327, 12.41410, 
+51.31304, 12.41461, 
+51.31298, 12.41483, 
+51.31293, 12.41494, 
+51.31295, 12.41497, 
+51.31293, 12.41498, 
+51.31296, 12.41495, 
+51.31317, 12.41459, 
+51.31317, 12.41457, 
+51.31316, 12.41444, 
+51.31316, 12.41439, 
+51.31334, 12.41391, 
+51.31371, 12.41332, 
+51.31399, 12.41286, 
+51.31422, 12.41249, 
+51.31465, 12.40956, 
+51.31465, 12.40949, 
+51.31465, 12.40949, 
+51.31465, 12.40945, 
+51.31464, 12.40936, 
+51.31464, 12.40936, 
+51.31464, 12.40936, 
+51.31464, 12.40936, 
+51.31464, 12.40936, 
+51.31512, 12.41022, 
+51.31517, 12.41034, 
+51.31509, 12.41022, 
+51.31506, 12.41031, 
+51.31496, 12.41036, 
+51.31485, 12.40939, 
+51.31484, 12.40938, 
+51.31484, 12.40945, 
+51.31486, 12.40930, 
+51.31412, 12.40669, 
+51.31396, 12.40623, 
+51.31370, 12.40579, 
+51.31334, 12.40497, 
+51.31270, 12.40350, 
+51.31221, 12.40235, 
+51.31185, 12.40145, 
+51.31140, 12.40011, 
+51.31101, 12.39885, 
+51.31066, 12.39779, 
+51.31050, 12.39728, 
+51.31043, 12.39698, 
+51.30961, 12.39358, 
+51.30946, 12.39236, 
+51.30931, 12.39060, 
+51.30924, 12.38872, 
+51.30928, 12.38751, 
+51.30943, 12.38620, 
+51.30962, 12.38478, 
+51.30985, 12.38313, 
+51.31010, 12.38143, 
+51.31024, 12.38029, 
+51.31027, 12.37932, 
+51.31032, 12.37870, 
+51.31038, 12.37778, 
+51.31048, 12.37646, 
+51.31060, 12.37526, 
+51.31068, 12.37448, 
+51.31072, 12.37411, 
+51.30883, 12.37343, 
+51.30854, 12.37345, 
+51.30777, 12.37349, 
+51.30718, 12.37357, 
+51.30658, 12.37362, 
+51.30542, 12.37378, 
+51.30472, 12.37395, 
+51.30380, 12.37424, 
+51.30322, 12.37419, 
+51.30267, 12.37387, 
+51.30224, 12.37362, 
+51.30188, 12.37324, 
+51.30178, 12.37309, 
+51.30161, 12.37265, 
+51.30170, 12.37224, 
+51.30179, 12.37179, 
+51.30206, 12.37150, 
+51.30223, 12.37154, 
+51.30242, 12.37171, 
+51.30243, 12.37208, 
+51.30226, 12.37251, 
+51.30161, 12.37379, 
+51.30097, 12.37475, 
+51.30044, 12.37540, 
+51.29965, 12.37603, 
+51.29877, 12.37646, 
+51.29787, 12.37656, 
+51.29688, 12.37664, 
+51.29528, 12.37674, 
+51.29335, 12.37755, 
+51.29225, 12.37790, 
+51.29114, 12.37803, 
+51.28943, 12.37808, 
+51.28728, 12.37854, 
+51.28639, 12.37917, 
+51.28505, 12.38029, 
+51.28343, 12.38171, 
+51.28219, 12.38266, 
+51.28127, 12.38312, 
+51.28032, 12.38329, 
+51.27890, 12.38341, 
+51.27738, 12.38336, 
+51.27595, 12.38314, 
+51.27460, 12.38279, 
+51.27271, 12.38222, 
+51.27198, 12.38200, 
+51.27083, 12.38165, 
+51.26981, 12.38146, 
+51.26827, 12.38132, 
+51.26680, 12.38136, 
+51.26530, 12.38163, 
+51.26381, 12.38204, 
+51.26292, 12.38230, 
+51.26111, 12.38289, 
+51.26060, 12.38306, 
+51.25979, 12.38326, 
+51.25847, 12.38358, 
+51.25635, 12.38404, 
+51.25462, 12.38438, 
+51.25299, 12.38462, 
+51.25178, 12.38484, 
+51.25046, 12.38514, 
+51.24874, 12.38572, 
+51.24735, 12.38627, 
+51.24566, 12.38703, 
+51.24378, 12.38776, 
+51.24205, 12.38833, 
+51.24094, 12.38848, 
+51.24035, 12.38856, 
+51.23932, 12.38862, 
+51.23828, 12.38861, 
+51.23688, 12.38859, 
+51.23538, 12.38857, 
+51.23290, 12.38852, 
+51.23119, 12.38835, 
+51.23028, 12.38822, 
+51.22924, 12.38808, 
+51.22801, 12.38798, 
+51.22402, 12.38775, 
+51.22241, 12.38767, 
+51.22061, 12.38760, 
+51.21923, 12.38760, 
+51.21784, 12.38787, 
+51.21672, 12.38832, 
+51.21544, 12.38914, 
+51.21442, 12.39003, 
+51.21347, 12.39113, 
+51.21263, 12.39234, 
+51.21179, 12.39392, 
+51.21103, 12.39570, 
+51.20998, 12.39856, 
+51.20837, 12.40303, 
+51.20728, 12.40607, 
+51.20622, 12.40904, 
+51.20511, 12.41198, 
+51.20408, 12.41444, 
+51.20304, 12.41667, 
+51.20178, 12.41929, 
+51.20052, 12.42208, 
+51.20007, 12.42366, 
+51.19955, 12.42597, 
+51.19889, 12.42878, 
+51.19794, 12.43220, 
+51.19710, 12.43514, 
+51.19641, 12.43786, 
+51.19613, 12.43967, 
+51.19604, 12.44114, 
+51.19611, 12.44297, 
+51.19629, 12.44543, 
+51.19652, 12.44853, 
+51.19649, 12.45027, 
+51.19624, 12.45172, 
+51.19587, 12.45351, 
+51.19534, 12.45619, 
+51.19509, 12.45764, 
+51.19467, 12.46005, 
+51.19422, 12.46184, 
+51.19378, 12.46312, 
+51.19322, 12.46464, 
+51.19259, 12.46635, 
+51.19206, 12.46768, 
+51.19129, 12.46952, 
+51.19051, 12.47131, 
+51.18976, 12.47302, 
+51.18881, 12.47520, 
+51.18831, 12.47632, 
+51.18772, 12.47736, 
+51.18722, 12.47796, 
+51.18630, 12.47869, 
+51.18520, 12.47960, 
+51.18455, 12.48015, 
+51.18388, 12.48072, 
+51.18320, 12.48129, 
+51.18213, 12.48221, 
+51.18114, 12.48306, 
+51.18011, 12.48393, 
+51.17862, 12.48528, 
+51.17711, 12.48665, 
+51.17544, 12.48820, 
+51.17471, 12.48888, 
+51.17336, 12.49012, 
+51.17185, 12.49153, 
+51.17009, 12.49316, 
+51.16809, 12.49501, 
+51.16676, 12.49625, 
+51.16529, 12.49762, 
+51.16389, 12.49892, 
+51.16195, 12.50074, 
+51.15981, 12.50286, 
+51.15812, 12.50470, 
+51.15636, 12.50680, 
+51.15567, 12.50746, 
+51.15507, 12.50786, 
+51.15428, 12.50815, 
+51.15340, 12.50844, 
+51.15246, 12.50872, 
+51.15185, 12.50891, 
+51.15115, 12.50915, 
+51.15013, 12.50946, 
+51.14901, 12.50965, 
+51.14794, 12.50969, 
+51.14700, 12.50972, 
+51.14537, 12.50987, 
+51.14380, 12.50999, 
+51.14265, 12.51008, 
+51.14102, 12.51003, 
+51.14007, 12.50992, 
+51.13942, 12.50984, 
+51.13862, 12.50975, 
+51.13799, 12.50955, 
+51.13772, 12.50943, 
+51.13750, 12.50929, 
+51.13739, 12.50922, 
+51.13694, 12.50894, 
+51.13682, 12.50886, 
+51.13608, 12.50837, 
+51.13550, 12.50798, 
+51.13441, 12.50725, 
+51.13326, 12.50647, 
+51.13245, 12.50600, 
+51.13152, 12.50563, 
+51.13032, 12.50517, 
+51.12969, 12.50497, 
+51.12894, 12.50471, 
+51.12822, 12.50450, 
+51.12693, 12.50178, 
+51.12656, 12.50063, 
+51.12630, 12.49978, 
+51.12614, 12.49874, 
+51.12601, 12.49745, 
+51.12578, 12.49588, 
+51.12546, 12.49462, 
+51.12506, 12.49352, 
+51.12446, 12.49225, 
+51.12382, 12.49121, 
+51.12281, 12.48996, 
+51.12245, 12.48951, 
+51.12201, 12.48900, 
+51.12141, 12.48836, 
+51.12105, 12.48797, 
+51.12077, 12.48739, 
+51.12072, 12.48720, 
+51.12029, 12.48563, 
+51.11970, 12.48428, 
+51.11935, 12.48401, 
+51.11906, 12.48407, 
+51.11886, 12.48418, 
+51.11790, 12.48487, 
+51.11742, 12.48522, 
+51.11675, 12.48575, 
+51.11627, 12.48616, 
+51.11543, 12.48687, 
+51.11463, 12.48756, 
+51.11371, 12.48825, 
+51.11333, 12.48853, 
+51.11301, 12.48877, 
+51.11276, 12.48896, 
+51.11248, 12.48917, 
+51.11212, 12.48957, 
+51.11156, 12.49029, 
+51.11097, 12.49098, 
+51.11060, 12.49114, 
+51.11046, 12.49116, 
+51.10966, 12.49109, 
+51.10883, 12.49082, 
+51.10813, 12.49034, 
+51.10742, 12.48967, 
+51.10680, 12.48888, 
+51.10606, 12.48784, 
+51.10529, 12.48676, 
+51.10461, 12.48581, 
+51.10361, 12.48441, 
+51.10273, 12.48302, 
+51.10208, 12.48161, 
+51.10131, 12.47986, 
+51.10064, 12.47888, 
+51.09990, 12.47809, 
+51.09887, 12.47730, 
+51.09691, 12.47601, 
+51.09526, 12.47491, 
+51.09426, 12.47418, 
+51.09345, 12.47320, 
+51.09260, 12.47237, 
+51.09185, 12.47178, 
+51.09107, 12.47117, 
+51.09021, 12.47046, 
+51.08925, 12.46975, 
+51.08836, 12.46926, 
+51.08718, 12.46866, 
+51.08609, 12.46826, 
+51.08453, 12.46767, 
+51.08360, 12.46700, 
+51.08170, 12.46562, 
+51.08137, 12.46543, 
+51.08043, 12.46511, 
+51.07919, 12.46482, 
+51.07797, 12.46453, 
+51.07690, 12.46425, 
+51.07575, 12.46396, 
+51.07501, 12.46359, 
+51.07438, 12.46310, 
+51.07392, 12.46250, 
+51.07331, 12.46164, 
+51.07288, 12.46106, 
+51.07242, 12.46039, 
+51.07172, 12.45942, 
+51.07029, 12.45744, 
+51.06939, 12.45619, 
+51.06787, 12.45409, 
+51.06758, 12.45381, 
+51.06701, 12.45350, 
+51.06672, 12.45348, 
+51.06579, 12.45346, 
+51.06486, 12.45355, 
+51.06436, 12.45375, 
+51.06362, 12.45399, 
+51.06280, 12.45405, 
+51.06258, 12.45406, 
+51.06215, 12.45384, 
+51.06178, 12.45348, 
+51.06146, 12.45347, 
+51.06134, 12.45352, 
+51.06047, 12.45388, 
+51.05968, 12.45420, 
+51.05830, 12.45477, 
+51.05796, 12.45488, 
+51.05727, 12.45477, 
+51.05630, 12.45439, 
+51.05493, 12.45386, 
+51.05454, 12.45372, 
+51.05403, 12.45349, 
+51.05338, 12.45317, 
+51.05332, 12.45316, 
+51.05292, 12.45322, 
+51.05190, 12.45364, 
+51.05060, 12.45420, 
+51.04975, 12.45444, 
+51.04888, 12.45471, 
+51.04741, 12.45519, 
+51.04662, 12.45540, 
+51.04585, 12.45539, 
+51.04422, 12.45532, 
+51.04308, 12.45536, 
+51.04232, 12.45568, 
+51.04161, 12.45632, 
+51.04058, 12.45735, 
+51.03970, 12.45789, 
+51.03872, 12.45824, 
+51.03732, 12.45865, 
+51.03579, 12.45888, 
+51.03481, 12.45888, 
+51.03388, 12.45861, 
+51.03243, 12.45809, 
+51.03149, 12.45800, 
+51.02979, 12.45810, 
+51.02916, 12.45811, 
+51.02856, 12.45809, 
+51.02759, 12.45810, 
+51.02663, 12.45809, 
+51.02572, 12.45786, 
+51.02479, 12.45750, 
+51.02387, 12.45689, 
+51.02193, 12.45524, 
+51.02099, 12.45475, 
+51.02003, 12.45462, 
+51.01878, 12.45447, 
+51.01789, 12.45437, 
+51.01689, 12.45425, 
+51.01572, 12.45412, 
+51.01468, 12.45400, 
+51.01351, 12.45401, 
+51.01261, 12.45425, 
+51.01166, 12.45473, 
+51.01079, 12.45543, 
+51.01000, 12.45641, 
+51.00914, 12.45752, 
+51.00788, 12.45894, 
+51.00639, 12.46046, 
+51.00569, 12.46139, 
+51.00515, 12.46239, 
+51.00455, 12.46373, 
+51.00349, 12.46626, 
+51.00280, 12.46756, 
+51.00200, 12.46865, 
+51.00113, 12.46955, 
+51.00010, 12.47027, 
+50.99898, 12.47072, 
+50.99813, 12.47089, 
+50.99709, 12.47091, 
+50.99606, 12.47064, 
+50.99497, 12.47020, 
+50.99298, 12.46923, 
+50.99114, 12.46834, 
+50.98960, 12.46759, 
+50.98795, 12.46679, 
+50.98599, 12.46599, 
+50.98478, 12.46568, 
+50.98336, 12.46564, 
+50.98183, 12.46559, 
+50.98029, 12.46536, 
+50.97898, 12.46487, 
+50.97768, 12.46409, 
+50.97651, 12.46313, 
+50.97544, 12.46200, 
+50.97445, 12.46063, 
+50.97356, 12.45901, 
+50.97278, 12.45729, 
+50.97154, 12.45396, 
+50.97015, 12.45028, 
+50.96886, 12.44684, 
+50.96773, 12.44382, 
+50.96609, 12.43942, 
+50.96487, 12.43614, 
+50.96441, 12.43462, 
+50.96408, 12.43325, 
+50.96368, 12.43120, 
+50.96339, 12.42902, 
+50.96312, 12.42697, 
+50.96269, 12.42394, 
+50.96221, 12.42166, 
+50.96158, 12.41949, 
+50.96086, 12.41767, 
+50.96003, 12.41584, 
+50.95911, 12.41416, 
+50.95835, 12.41302, 
+50.95763, 12.41208, 
+50.95670, 12.41101, 
+50.95561, 12.41004, 
+50.95454, 12.40919, 
+50.95298, 12.40808, 
+50.95177, 12.40728, 
+50.95030, 12.40625, 
+50.94977, 12.40583, 
+50.94880, 12.40501, 
+50.94818, 12.40448, 
+50.94725, 12.40368, 
+50.94652, 12.40305, 
+50.94566, 12.40232, 
+50.94452, 12.40138, 
+50.94389, 12.40086, 
+50.94268, 12.39994, 
+50.94166, 12.39920, 
+50.94114, 12.39902, 
+50.94116, 12.39911, 
+50.94148, 12.39995, 
+50.94205, 12.40134, 
+50.94238, 12.40234, 
+50.94258, 12.40331, 
+50.94270, 12.40416, 
+50.94284, 12.40604, 
+50.94295, 12.40750, 
+50.94289, 12.40862, 
+50.94282, 12.41003, 
+50.94280, 12.41110, 
+50.94276, 12.41193, 
+50.94270, 12.41220, 
+50.94248, 12.41254, 
+50.94172, 12.41331, 
+50.94120, 12.41378, 
+50.94091, 12.41392, 
+50.94049, 12.41396, 
+50.94017, 12.41403, 
+50.93989, 12.41409, 
+50.93948, 12.41441, 
+50.93908, 12.41473, 
+50.93859, 12.41478, 
+50.93795, 12.41471, 
+50.93730, 12.41467, 
+50.93648, 12.41495, 
+50.93597, 12.41516, 
+50.93535, 12.41545, 
+50.93492, 12.41583, 
+50.93448, 12.41640, 
+50.93441, 12.41649, 
+50.93396, 12.41687, 
+50.93372, 12.41728, 
+50.93370, 12.41752, 
+50.93367, 12.41811, 
+50.93368, 12.41818, 
+50.93373, 12.41847, 
+50.93378, 12.41880, 
+50.93375, 12.41929, 
+50.93373, 12.41937, 
+50.93359, 12.41977, 
+50.93331, 12.42035, 
+50.93312, 12.42074, 
+50.93309, 12.42075, 
+50.93289, 12.42087, 
+50.93231, 12.42119, 
+50.93179, 12.42153, 
+50.93146, 12.42193, 
+50.93111, 12.42231, 
+50.93065, 12.42248, 
+50.93057, 12.42248, 
+50.93021, 12.42231, 
+50.93013, 12.42227, 
+50.92986, 12.42243, 
+50.92969, 12.42273, 
+50.92943, 12.42347, 
+50.92898, 12.42415, 
+50.92869, 12.42456, 
+50.92838, 12.42498, 
+50.92810, 12.42539, 
+50.92743, 12.42637, 
+50.92732, 12.42654, 
+50.92714, 12.42657, 
+50.92711, 12.42657, 
+50.92688, 12.42664, 
+50.92677, 12.42696, 
+50.92649, 12.42758, 
+50.92603, 12.42820, 
+50.92523, 12.42912, 
+50.92435, 12.43008, 
+50.92374, 12.43058, 
+50.92326, 12.43098, 
+50.92292, 12.43125, 
+50.92262, 12.43150, 
+50.92218, 12.43201, 
+50.92196, 12.43229, 
+50.92186, 12.43241, 
+50.92181, 12.43263, 
+50.92190, 12.43281, 
+50.92216, 12.43338, 
+50.92235, 12.43440, 
+50.92236, 12.43454, 
+50.92242, 12.43524, 
+50.92245, 12.43580, 
+50.92241, 12.43635, 
+50.92228, 12.43684, 
+50.92213, 12.43764, 
+50.92210, 12.43856, 
+50.92210, 12.43897, 
+50.92197, 12.43961, 
+50.92189, 12.43973, 
+50.92133, 12.44067, 
+50.92090, 12.44099, 
+50.92061, 12.44111, 
+50.92019, 12.44160, 
+50.92009, 12.44210, 
+50.92009, 12.44231, 
+50.92013, 12.44295, 
+50.92021, 12.44361, 
+50.92021, 12.44414, 
+50.92014, 12.44459, 
+50.92009, 12.44496, 
+50.91991, 12.44493, 
+50.91939, 12.44478, 
+50.91881, 12.44461, 
+50.91795, 12.44436, 
+50.91728, 12.44416, 
+50.91625, 12.44385, 
+50.91494, 12.44347, 
+50.91432, 12.44328, 
+50.91345, 12.44303, 
+50.91240, 12.44271, 
+50.91163, 12.44253, 
+50.91119, 12.44245, 
+50.91085, 12.44223, 
+50.91050, 12.44187, 
+50.91008, 12.44164, 
+50.90939, 12.44138, 
+50.90855, 12.44106, 
+50.90763, 12.44073, 
+50.90686, 12.44045, 
+50.90550, 12.43996, 
+50.90494, 12.44001, 
+50.90390, 12.44021, 
+50.90279, 12.44043, 
+50.90157, 12.44073, 
+50.90086, 12.44077, 
+50.90012, 12.44047, 
+50.89959, 12.44005, 
+50.89912, 12.43932, 
+50.89875, 12.43875, 
+50.89830, 12.43820, 
+50.89739, 12.43721, 
+50.89642, 12.43616, 
+50.89566, 12.43536, 
+50.89516, 12.43498, 
+50.89432, 12.43453, 
+50.89349, 12.43410, 
+50.89271, 12.43371, 
+50.89191, 12.43344, 
+50.89107, 12.43352, 
+50.89058, 12.43357, 
+50.89023, 12.43362, 
+50.88976, 12.43370, 
+50.88908, 12.43386, 
+50.88864, 12.43399, 
+50.88850, 12.43378, 
+50.88849, 12.43367, 
+50.88836, 12.43254, 
+50.88834, 12.43240, 
+50.88824, 12.43202, 
+50.88780, 12.43101, 
+50.88753, 12.43078, 
+50.88726, 12.43086, 
+50.88671, 12.43103, 
+50.88612, 12.43096, 
+50.88539, 12.43067, 
+50.88531, 12.43065, 
+50.88507, 12.43064, 
+50.88454, 12.43036, 
+50.88417, 12.43014, 
+50.88369, 12.43012, 
+50.88323, 12.43046, 
+50.88294, 12.43066, 
+50.88220, 12.43101, 
+50.88210, 12.43108, 
+50.88155, 12.43163, 
+50.88090, 12.43223, 
+50.88027, 12.43262, 
+50.87958, 12.43292, 
+50.87884, 12.43323, 
+50.87812, 12.43355, 
+50.87732, 12.43390, 
+50.87664, 12.43432, 
+50.87581, 12.43486, 
+50.87536, 12.43516, 
+50.87470, 12.43513, 
+50.87404, 12.43503, 
+50.87316, 12.43481, 
+50.87260, 12.43466, 
+50.87216, 12.43434, 
+50.87206, 12.43421, 
+50.87135, 12.43340, 
+50.87061, 12.43275, 
+50.86996, 12.43206, 
+50.86941, 12.43147, 
+50.86822, 12.43046, 
+50.86718, 12.42966, 
+50.86636, 12.42927, 
+50.86571, 12.42912, 
+50.86482, 12.42906, 
+50.86414, 12.42902, 
+50.86351, 12.42868, 
+50.86246, 12.42812, 
+50.86172, 12.42779, 
+50.86097, 12.42736, 
+50.86039, 12.42687, 
+50.85994, 12.42654, 
+50.85980, 12.42648, 
+50.85949, 12.42649, 
+50.85917, 12.42658, 
+50.85879, 12.42640, 
+50.85872, 12.42619, 
+50.85853, 12.42520, 
+50.85847, 12.42485, 
+50.85831, 12.42450, 
+50.85804, 12.42447, 
+50.85794, 12.42424, 
+50.85794, 12.42377, 
+50.85799, 12.42333, 
+50.85811, 12.42258, 
+50.85822, 12.42165, 
+50.85817, 12.42106, 
+50.85804, 12.42088, 
+50.85768, 12.42042, 
+50.85765, 12.42036, 
+50.85750, 12.41992, 
+50.85747, 12.41912, 
+50.85748, 12.41859, 
+50.85749, 12.41841, 
+50.85750, 12.41818, 
+50.85751, 12.41791, 
+50.85751, 12.41780, 
+50.85771, 12.41791, 
+50.85771, 12.41796, 
+50.85771, 12.41797, 
+50.85779, 12.41793, 
+50.85772, 12.41785, 
+50.85778, 12.41797, 
+50.85770, 12.41784, 
+50.85777, 12.41791, 
+50.85778, 12.41794, 
+50.85778, 12.41796, 
index 1bd748d19407a7e4a36b0a703df9b64e323abfec..13aa45d6c02622d71c51cfea8cf164c09e6ea803 100644 (file)
@@ -4,6 +4,11 @@ rm -f ${TMPDIR}/gl.loc
 gpsbabel -i geo -f ${REFERENCE}/geocaching.loc -o geo -F ${TMPDIR}/gl.loc
 compare ${TMPDIR}/gl.loc ${REFERENCE}
 
+# try with positional arugments
+rm -f ${TMPDIR}/gl.loc
+gpsbabel -i geo -o geo ${REFERENCE}/geocaching.loc ${TMPDIR}/gl.loc
+compare ${TMPDIR}/gl.loc ${REFERENCE}
+
 # we have a one off reader in geo, make sure it can read stdin.
 rm -f ${TMPDIR}/gl_si.loc
 cat ${REFERENCE}/geocaching.loc | gpsbabel -i geo -f - -o geo -F ${TMPDIR}/gl_si.loc
index 03d5c3e49660650fde64efb392cb2b5679e2f6a3..c7d54348413106f36f172c3337570045b417341f 100644 (file)
@@ -4,3 +4,6 @@
 gpsbabel -i iblue747 -f ${REFERENCE}/track/iblue747.csv -o gpx -F ${TMPDIR}/iblue747~csv.gpx
 compare ${REFERENCE}/track/iblue747~csv.gpx ${TMPDIR}/iblue747~csv.gpx
 
+gpsbabel -i iblue747 -o csv -f ${REFERENCE}/track/iblue747.csv -F ${TMPDIR}/iblue747~csv.csv
+compare ${REFERENCE}/track/iblue747~csv.csv ${TMPDIR}/iblue747~csv.csv
+
diff --git a/vecs.cc b/vecs.cc
index 9ac40b44a45c50e14f26a3dc83c0ded6e23e5c5a..a48a380aa19bda282b7b3242d0a9d2974bd90ce5 100644 (file)
--- a/vecs.cc
+++ b/vecs.cc
@@ -36,6 +36,7 @@
 #include <algorithm>           // for sort
 #include <cassert>             // for assert
 #include <cstdio>              // for printf, putchar, sscanf
+#include <type_traits>         // for add_const<>::type, is_base_of
 
 #include "defs.h"              // for arglist_t, ff_vecs_t, ff_cap, fatal, CSTR, ARGTYPE_TYPEMASK, case_ignore_strcmp, global_options, global_opts, warning, xfree, ARGTYPE_BOOL, ff_cap_read, ff_cap_write, ARGTYPE_HIDDEN, ff_type_internal, xstrdup, ARGTYPE_INT, ARGTYPE_REQUIRED, ARGTYPE_FLOAT
 #include "dg-100.h"            // for Dg100FileFormat, Dg100SerialFormat, Dg200FileFormat, Dg200SerialFormat
@@ -105,6 +106,13 @@ extern ff_vecs_t format_garmin_xt_vecs;
 
 #define MYNAME "vecs"
 
+template <typename T>
+Format* fmtfactory(const QString& filename)
+{
+  static_assert(std::is_base_of<Format, T>::value, "T must be derived from Format");
+  return new T(filename);
+}
+
 struct Vecs::Impl {
   /*
    * Having these LegacyFormat instances be non-static data members
@@ -113,10 +121,6 @@ struct Vecs::Impl {
    * instance is guaranteed to have already constructed when an instance
    * of this class is constructed.
    */
-#if CSVFMTS_ENABLED
-  XcsvFormat xcsv_fmt;
-#endif // CSVFMTS_ENABLED
-  GeoFormat geo_fmt;
   GpxFormat gpx_fmt;
   LegacyFormat garmin_fmt {garmin_vecs};
   GdbFormat gdb_fmt;
@@ -182,19 +186,21 @@ struct Vecs::Impl {
 #if CSVFMTS_ENABLED
     /* XCSV must be the first entry in this table. */
     {
-      &xcsv_fmt,
+      nullptr,
       "xcsv",
       "? Character Separated Values",
       nullptr,
       nullptr,
+      &fmtfactory<XcsvFormat>
     },
 #endif
     {
-      &geo_fmt,
+      nullptr,
       "geo",
       "Geocaching.com .loc",
       "loc",
       nullptr,
+      &fmtfactory<GeoFormat>
     },
     {
       &gpx_fmt,
@@ -595,18 +601,25 @@ Vecs& Vecs::Instance()
  * the default the default constructor would be implicitly deleted.
  */
 
+void Vecs::init_vec(Format* fmt)
+{
+  QVector<arglist_t>* args = fmt->get_args();
+  if (args && !args->isEmpty()) {
+    assert(args->isDetached());
+    for (auto& arg : *args) {
+      arg.argvalptr = nullptr;
+      if (arg.argval) {
+        *arg.argval = nullptr;
+      }
+    }
+  }
+}
+
 void Vecs::init_vecs()
 {
   for (const auto& vec : d_ptr_->vec_list) {
-    QVector<arglist_t>* args = vec.vec->get_args();
-    if (args && !args->isEmpty()) {
-      assert(args->isDetached());
-      for (auto& arg : *args) {
-        arg.argvalptr = nullptr;
-        if (arg.argval) {
-          *arg.argval = nullptr;
-        }
-      }
+    if (vec.vec != nullptr) {
+      init_vec(vec.vec);
     }
   }
   style_list = create_style_vec();
@@ -672,19 +685,26 @@ bool Vecs::is_bool(const QString& val)
          (!val.isEmpty() && val.at(0).isDigit());
 }
 
+void Vecs::exit_vec(Format* fmt)
+{
+  (fmt->exit)();
+  QVector<arglist_t>* args = fmt->get_args();
+  if (args && !args->isEmpty()) {
+    assert(args->isDetached());
+    for (auto& arg : *args) {
+      if (arg.argvalptr) {
+        xfree(arg.argvalptr);
+        *arg.argval = arg.argvalptr = nullptr;
+      }
+    }
+  }
+}
+
 void Vecs::exit_vecs()
 {
   for (const auto& vec : d_ptr_->vec_list) {
-    (vec.vec->exit)();
-    QVector<arglist_t>* args = vec.vec->get_args();
-    if (args && !args->isEmpty()) {
-      assert(args->isDetached());
-      for (auto& arg : *args) {
-        if (arg.argvalptr) {
-          xfree(arg.argvalptr);
-          *arg.argval = arg.argvalptr = nullptr;
-        }
-      }
+    if (vec.vec != nullptr) {
+      exit_vec(vec.vec);
     }
   }
   style_list.clear();
@@ -799,7 +819,7 @@ void Vecs::validate_options(const QStringList& options, const QVector<arglist_t>
   }
 }
 
-void Vecs::prepare_format(const fmtinfo_t& fmtdata) const
+void Vecs::prepare_format(const fmtinfo_t& fmtdata) 
 {
   QVector<arglist_t>* args = fmtdata->get_args();
 
@@ -838,7 +858,10 @@ void Vecs::prepare_format(const fmtinfo_t& fmtdata) const
    * that we are processing xcsv,style= and it was preceeded by an xcsv
    * format that utilized an internal style file.
    */
-  d_ptr_->xcsv_fmt.xcsv_setup_internal_style(fmtdata.style_filename);
+  auto* xcsvfmt = dynamic_cast<XcsvFormat*>(fmtdata.fmt);
+  if (xcsvfmt != nullptr) {
+    xcsvfmt->xcsv_setup_internal_style(fmtdata.style_filename);
+  }
 #endif // CSVFMTS_ENABLED
 }
 
@@ -855,9 +878,7 @@ Vecs::fmtinfo_t Vecs::find_vec(const QString& fmtargstring)
       continue;
     }
 
-    fmtinfo_t fmtinfo{vec.vec, vec.name, nullptr, options};
-    prepare_format(fmtinfo);
-    return fmtinfo;
+    return {vec.vec, vec.name, nullptr, options, vec.factory};
   }
 
   /*
@@ -869,9 +890,7 @@ Vecs::fmtinfo_t Vecs::find_vec(const QString& fmtargstring)
       continue;
     }
 
-    fmtinfo_t fmtinfo{d_ptr_->vec_list.at(0).vec, svec.name, svec.style_filename, options};
-    prepare_format(fmtinfo);
-    return fmtinfo;
+    return {d_ptr_->vec_list.at(0).vec, svec.name, svec.style_filename, options, d_ptr_->vec_list.at(0).factory};
   }
 
   /*
@@ -948,6 +967,7 @@ QVector<Vecs::vecinfo_t> Vecs::sort_and_unify_vecs() const
 
   /* Gather relevant information for normal formats. */
   for (const auto& vec : d_ptr_->vec_list) {
+    Format* fmt = (vec.factory != nullptr)? vec.factory("") : vec.vec;
     vecinfo_t info;
     info.name = vec.name;
     info.desc = vec.desc;
@@ -957,15 +977,18 @@ QVector<Vecs::vecinfo_t> Vecs::sort_and_unify_vecs() const
     } else {
       info.parent = vec.parent;
     }
-    info.type = vec.vec->get_type();
-    info.cap = vec.vec->get_cap();
-    const QVector<arglist_t>* args = vec.vec->get_args();
+    info.type = fmt->get_type();
+    info.cap = fmt->get_cap();
+    const QVector<arglist_t>* args = fmt->get_args();
     if (args != nullptr) {
       for (const auto& arg : *args) {
         info.arginfo.append(arginfo_t(arg));
       }
     }
     svp.append(info);
+    if (vec.factory != nullptr) {
+      delete fmt;
+    }
   }
 
 #if CSVFMTS_ENABLED
@@ -973,11 +996,13 @@ QVector<Vecs::vecinfo_t> Vecs::sort_and_unify_vecs() const
    * Make sure we know which entry in the vector list that is.
    */
   assert(d_ptr_->vec_list.at(0).name.compare("xcsv", Qt::CaseInsensitive) == 0);
+
+  Format* xcsvfmt = (d_ptr_->vec_list.at(0).factory != nullptr)? d_ptr_->vec_list.at(0).factory("") : d_ptr_->vec_list.at(0).vec;
   /* The style formats use a modified xcsv argument list that doesn't include
    * the option to set the style file.  Make sure we know which entry in
    * the argument list that is.
    */
-  assert(case_ignore_strcmp(d_ptr_->vec_list.at(0).vec->get_args()->at(0).helpstring,
+  assert(case_ignore_strcmp(xcsvfmt->get_args()->at(0).helpstring,
                             "Full path to XCSV style file") == 0);
 
   /* Gather the relevant info for the style based formats. */
@@ -1009,7 +1034,7 @@ QVector<Vecs::vecinfo_t> Vecs::sort_and_unify_vecs() const
      * 'Full path to XCSV style file' argument to any
      * GUIs for an internal format.
      */
-    const QVector<arglist_t>* args = d_ptr_->vec_list.at(0).vec->get_args();
+    const QVector<arglist_t>* args = xcsvfmt->get_args();
     if (args != nullptr) {
       bool first = true;
       for (const auto& arg : *args) {
@@ -1021,6 +1046,9 @@ QVector<Vecs::vecinfo_t> Vecs::sort_and_unify_vecs() const
     }
     svp.append(info);
   }
+  if (d_ptr_->vec_list.at(0).factory != nullptr) {
+    delete xcsvfmt;
+  }
 #endif // CSVFMTS_ENABLED
 
   /*
@@ -1276,7 +1304,11 @@ bool Vecs::validate_args(const QString& name, const QVector<arglist_t>* args)
 
 bool Vecs::validate_vec(const vecs_t& vec)
 {
-  bool ok = validate_args(vec.name, vec.vec->get_args());
+  Format* fmt = (vec.factory != nullptr)? vec.factory("") : vec.vec;
+  bool ok = validate_args(vec.name, fmt->get_args());
+  if (vec.factory != nullptr) {
+    delete fmt;
+  }
 
   return ok;
 }
diff --git a/vecs.h b/vecs.h
index dc9193cc1fab79359e46ba92fa2be1a386a5aee7..fcb15ee6565767f0e73de1ee12b834b3c1a186f0 100644 (file)
--- a/vecs.h
+++ b/vecs.h
 #ifndef VECS_H_INCLUDED_
 #define VECS_H_INCLUDED_
 
-#include <cstdint>              // for uint32_t
+#include <cstdint>      // for uint32_t
 
-#include <QString>              // for QString
-#include <QStringList>          // for QStringList
-#include <QVector>              // for QVector<>::iterator, QVector
+#include <QList>        // for QList
+#include <QString>      // for QString
+#include <QStringList>  // for QStringList
+#include <QVector>      // for QVector<>::iterator, QVector
 
 #include "defs.h"
 #include "format.h"
@@ -38,20 +39,26 @@ public:
 
   /* Types */
 
+  using FormatFactory = Format* (*)(const QString&);
+
   class fmtinfo_t {
   public:
 
+    bool isDynamic() {
+      return factory != nullptr;
+    }
     explicit operator bool() const {
-      return fmt != nullptr;
+      return ((fmt != nullptr) || (factory != nullptr));
     }
     Format* operator->() const {
       return fmt;
     }
 
-    Format* fmt{};
+    Format* fmt{nullptr};
     QString fmtname;
     QString style_filename;
     QStringList options;
+    FormatFactory factory{nullptr};
   };
 
   /* Special Member Functions */
@@ -64,13 +71,15 @@ public:
 
   /* Member Functions */
 
+  static void init_vec(Format* fmt);
   void init_vecs();
+  static void exit_vec(Format* fmt);
   void exit_vecs();
   static void assign_option(const QString& module, arglist_t* arg, const QString& val);
   static void disp_vec_options(const QString& vecname, const QVector<arglist_t>* args);
   static void validate_options(const QStringList& options, const QVector<arglist_t>* args, const QString& name);
   static QString get_option(const QStringList& options, const QString& argname);
-  void prepare_format(const fmtinfo_t& data) const;
+  static void prepare_format(const fmtinfo_t& data) ;
   fmtinfo_t find_vec(const QString& fmtargstring);
   void disp_vecs() const;
   void disp_vec(const QString& vecname) const;
@@ -90,6 +99,7 @@ private:
     QString desc;
     QString extensions; // list of possible extensions separated by '/', first is output default for GUI.
     QString parent;
+    FormatFactory factory{nullptr};
   };
 
   struct arginfo_t {
diff --git a/xcsv.h b/xcsv.h
index afa2711e4477b395919734bcb9a9e5c6ebad1929..97d581f798088b70a6750db407cec53e109dc042 100644 (file)
--- a/xcsv.h
+++ b/xcsv.h
@@ -262,6 +262,7 @@ private:
 class XcsvFormat : public Format
 {
 public:
+  using Format::Format;
   /* Member Functions */
   QVector<arglist_t>* get_args() override
   {